﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using ST.Common.Data;
using ST.Common.Util;
using ST.Common.Util.Model;
using ST.Common.Util.Mvc;
using ST.Buz.Base;
using ST.Buz.Base.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using ST.Buz.Base.Enums;
using ST.Common.Util.Security;

namespace ST.Buz.Service
{
	public partial interface IServiceSysOAuth
	{
		/// <summary>
		/// 小程序/网页授权认证注册/登录，返回会话信息（包含userid）
		/// </summary>
		/// <param name="oauthDetail"></param>
		/// <returns></returns>
		UserSession RegisterOrLogin(SessionType type, string appID, string openID, string unionID, string sessionKey, SysOAuthDetail oauthDetail);

		/// <summary>
		/// 只更新用户和OAuth基本信息（头像、昵称等）
		/// </summary>
		/// <returns></returns>
		UserSession Update(UserSession sessionCurrent, SessionType oauthType, string appID, SysOAuthDetail oauthDetail, string mpAppID);

		///// <summary>
		///// 刷新OAuth认证的基本信息，并返回更新后的值
		///// </summary>
		///// <returns></returns>
		//UserSession Refresh(UserSession sessionCurrent);

		/// <summary>
		/// 根据请求头部的认证信息刷新会话
		/// </summary>
		UserSession Refresh(UserSession sessionCurrent, SessionType type, string appID);

		/// <summary>
		/// 使用用户名密码登录，登录成功后与当前会话绑定合并，返回更新后的会话信息
		/// </summary>
		/// <returns></returns>
		UserSession Bind(UserSession sessionCurrent, SessionType type, string appID, string userCode, string userPasswd, SysOAuthDetail oauthDetail);

		/// <summary>
		/// 将小程序用户与公众号用户绑定，绑定成功后与当前会话绑定合并，返回更新后的会话信息
		/// </summary>
		/// <param name="sessionCurrent"></param>
		/// <param name="appID">小程序appid</param>
		/// <param name="oauthDetail"></param>
		/// <returns></returns>
		UserSession MPBind(UserSession sessionCurrent, string appID, SysOAuthDetail oauthDetail);

		/// <summary>
		/// 解除绑定
		/// </summary>
		/// <returns></returns>
		UserSession Unbind(UserSession sessionCurrent, string appID);

		/// <summary>
		/// 根据appID和openID获取用户授权信息
		/// </summary>
		/// <param name="appID"></param>
		/// <param name="openID"></param>
		/// <returns></returns>
		Sys_OAuth Get(string appID, string openID);

		void DeleteByUserID(int userID);

	}

	public partial class ServiceSysOAuth
	{
		private readonly IServiceSysUserOAuth serviceUserOAuth;
		private readonly IServiceSysSession serviceSession;
		private readonly IServiceSysUserRole serviceUserRole;
		public ServiceSysOAuth(BuzContext ctx,
			IServiceSysUserOAuth _serviceUserOAuth,
			IServiceSysSession _serviceSession,
			IServiceSysUserRole _serviceUserRole,
			ILogger<ServiceSysOAuth> log)
		{
			context = ctx;
			logger = log;

			serviceUserOAuth = _serviceUserOAuth;
			serviceSession = _serviceSession;
			serviceUserRole = _serviceUserRole;
		}

		/// <summary>
		/// 生成用户会话信息
		/// </summary>
		/// <param name="user"></param>
		/// <param name="oauth"></param>
		/// <param name="session"></param>
		/// <param name="updateRoles">是否更新当前会话里的用户角色信息</param>
		/// <returns></returns>
		private UserSession GetUserSession(UserSession sessionCurrent, Sys_User user, Sys_OAuth oauth, Sys_Session session, bool updateRoles = true)
		{
			if (user == null || oauth == null || session == null)
			{
				throw new ArgumentException("生成用户会话信息参数不能为空");
			}
			if (sessionCurrent == null)
			{
				sessionCurrent = new UserSession();
			}
			if (oauth != null && oauth.RelatedOAuthID > 0)
			{
				var oauthRelated = context.SysOAuth.SingleOrDefault(m => m.ID == oauth.RelatedOAuthID);
				if (oauthRelated != null)
				{
					sessionCurrent.RelatedOpenID = oauthRelated.OpenID;
					sessionCurrent.Subscribe = oauthRelated.Subscribed;
				}
			}
			sessionCurrent.OrgID = user.OrgID;
			sessionCurrent.OpenID = oauth.OpenID;
			sessionCurrent.UnionID = oauth.UnionID;
			sessionCurrent.SessionType = session.Type;
			sessionCurrent.Sessionkey = session.SessionKey;
			sessionCurrent.Timestamp = session.LastVisit.Ticks;
			sessionCurrent.Avatar = user.AvatarUrl;
			sessionCurrent.DeptID = user.DeptID;
			sessionCurrent.LastLoginDate = user.LastLoginDate.HasValue ? user.LastLoginDate.Value.ToString("yyyy-MM-dd HH:mm:ss") : "";
			sessionCurrent.LastLoginIP = user.LastLoginIP;
			sessionCurrent.RoleType = user.RoleType;
			sessionCurrent.UserType = user.UserType;
			sessionCurrent.SessionID = session.ID;
			sessionCurrent.UserID = user.ID;
			sessionCurrent.UserCode = user.Code;
			sessionCurrent.State = user.StateNow;
			sessionCurrent.UserName = user.Name;
			//userSession.OrgName = user.OrgName;
			//userSession.DeptName = user.DeptName;
			#region todo:其他自定义session字段
			//获取单位绑定的PartnerID
			if (sessionCurrent.UserType > 0 && sessionCurrent.OrgID > 0)
			{
				var org = context.SysOrganization.FirstOrDefault(m => m.ID == sessionCurrent.OrgID);
				if (org != null)
				{
					sessionCurrent.OrgType = org.Type;
					sessionCurrent.OrgPartnerID = org.PartnerID;
				}
			}
			#endregion

			if (updateRoles)
			{
				sessionCurrent.Roles = serviceUserRole.GetRolesArray(user.ID);
			}
			return sessionCurrent;
		}

		/// <summary>
		/// 根据appID和openID获取用户授权信息
		/// </summary>
		/// <param name="appID"></param>
		/// <param name="openID"></param>
		/// <returns></returns>
		public Sys_OAuth Get(string appID, string openID)
		{
			if (string.IsNullOrEmpty(appID) || string.IsNullOrEmpty(openID))
			{
				throw new ArgumentException("AppID或OpenID不能为空");
			}
			Sys_OAuth oauth = context.SysOAuth.SingleOrDefault(e => e.AppID == appID && e.OpenID == openID);
			return oauth;
		}

		/// <summary>
		/// 网页/小程序授权认证注册/登录，返回会话信息（包含userid）
		/// </summary>
		/// <param name="oauthDetail"></param>
		/// <returns></returns>
		public UserSession RegisterOrLogin(SessionType oauthType, string appID, string openID, string unionID, string sessionKey, SysOAuthDetail oauthDetail)
		{
			UserSession authSession = null;
			try
			{
				if (logger.IsEnabled(LogLevel.Debug))
				{
					logger.LogDebug("参数->" + JsonConvert.SerializeObject(oauthDetail));
				}
				if (string.IsNullOrEmpty(appID))
				{
					throw new BuzException("AppID不能为空");
				}
				if (string.IsNullOrEmpty(openID))
				{
					throw new BuzException("OpenID不能为空");
				}
				if (string.IsNullOrEmpty(sessionKey))
				{
					throw new BuzException("会话Key不能为空");
				}
				using (var trans = context.Database.BeginTransaction())
				{
					try
					{
						#region 事务具体操作
						DateTime dtNow = DateTime.Now;
						int userID = 0;
						string ip = GetRequestIP();
						string userCode = EncryptHelper.MD5Hash(appID + openID);//根据appid和openid生成usercode，然后查找用户表看之前是否授权登录过
						Sys_OAuth oauth = null;
						Sys_User user = null;
						Sys_Session session = null;
						oauth = context.SysOAuth.SingleOrDefault(e => e.AppID == appID && e.OpenID == openID);
						if (oauth != null)
						{
							if (oauth.UserID > 0)
							{
								user = context.SysUser.SingleOrDefault(m => m.ID == oauth.UserID);//获取oauth授权登录生成的user信息
							}
						}
						else
						{
							user = context.SysUser.SingleOrDefault(e => e.Code == userCode);//如果没绑定根据生成的code查询
						}

						if (user == null)
						{
							user = new Sys_User()
							{
								Code = userCode,
								PasswdSalt = Guid.NewGuid().ToString("N"),
								StateNow = (int)UserState.未授权,
								AddDate = dtNow,
								LastLoginDate = dtNow,
								LastLoginIP = ip
							};
							user.Passwd = EncryptHelper.SHA1Hash(openID + user.PasswdSalt);
							userID = RegisterOrLogin(user, oauthDetail);
						}
						else
						{
							userID = user.ID;
							user.LastLoginDate = dtNow;
							user.LastLoginIP = ip;
							RegisterOrLogin(user, oauthDetail);
						}

						if (oauth == null)
						{
							oauth = new Sys_OAuth
							{
								SessionKey = sessionKey,
								Type = (int)oauthType,
								AppID = appID,
								OpenID = openID,
								UnionID = unionID,
								UserID = userID,
								AddDate = dtNow,
								LastUpdate = dtNow,
								LastVisit = dtNow,
								LastVisitIP = ip
							};
							if (oauthDetail != null)
							{
								oauth.Authorized = true;
								#region 设置用户oauth信息
								oauth.NickName = oauthDetail.NickName;
								oauth.Gender = oauthDetail.Gender;
								oauth.AvatarUrl = oauthDetail.AvatarUrl;
								oauth.Country = oauthDetail.Country;
								oauth.Province = oauthDetail.Province;
								oauth.City = oauthDetail.City;
								oauth.District = oauthDetail.District;
								oauth.Town = oauthDetail.Town;
								oauth.DetailAddress = oauthDetail.DetailAddress;
								#endregion
							}
							context.SysOAuth.Add(oauth);
							context.SaveChanges();
						}
						else
						{
							oauth.UserID = userID;
							oauth.UnionID = unionID;
							oauth.Type = (int)oauthType;
							oauth.SessionKey = sessionKey;
							oauth.LastUpdate = dtNow;
							oauth.LastVisit = dtNow;
							oauth.LastVisitIP = ip;
							if (oauthDetail != null)
							{
								oauth.Authorized = true;
								#region 设置用户oauth信息
								oauth.NickName = oauthDetail.NickName;
								oauth.Gender = oauthDetail.Gender;
								oauth.AvatarUrl = oauthDetail.AvatarUrl;
								oauth.Country = oauthDetail.Country;
								oauth.Province = oauthDetail.Province;
								oauth.City = oauthDetail.City;
								oauth.District = oauthDetail.District;
								oauth.Town = oauthDetail.Town;
								oauth.DetailAddress = oauthDetail.DetailAddress;
								#endregion
							}
							context.SaveChanges();
						}

						session = context.SysSession.SingleOrDefault(e => e.UserID == userID && e.Type == (int)oauthType);//同一个用户同一种登录类型只能有一条记录
						if (session == null)
						{
							session = new Sys_Session
							{
								UserID = userID,
								Type = (int)oauthType,
								SessionKey = sessionKey,
								AddTime = dtNow,
								LastUpdate = dtNow,
								LastVisit = dtNow,
								LastVisitIP = ip
							};
							context.SysSession.Add(session);
							context.SaveChanges();
						}
						else
						{
							session.SessionKey = sessionKey;
							session.LastUpdate = dtNow;
							session.LastVisit = dtNow;
							session.LastVisitIP = ip;
							context.SaveChanges();
						}

						#region 获取绑定的用户信息
						Sys_User userBind = serviceUserOAuth.GetFirstOrDefaultUser(oauth.ID);
						//if (null != userBind && userBind.OrgID > 0)
						//{
						//	var org = context.SysOrganization.FirstOrDefault(m => m.ID == userBind.OrgID);
						//	if (null != org)
						//	{
						//		userBind.OrgName = org.Name;
						//	}
						//}
						#endregion

						#endregion
						trans.Commit();

						authSession = GetUserSession(null, userBind == null ? user : userBind, oauth, session);
					}
					catch (Exception ex)
					{
						trans.Rollback();
						throw ex;
					}
				}
			}
			catch (BuzException ex)
			{
				throw ex;
			}
			catch (DbUpdateException ex)
			{
				logger.LogError(ex.InnerException ?? ex, "更新数据库用户及会话信息出错");
				throw new BuzException("更新数据库用户及会话信息失败，" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, "更新用户及会话信息出错");
				throw new BuzException("更新用户及会话信息失败，" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
			}

			return authSession;
		}

		/// <summary>
		/// 只更新用户和OAuth基本信息（头像、昵称等）
		/// </summary>
		/// <returns></returns>
		public UserSession Update(UserSession sessionCurrent, SessionType oauthType, string appID, SysOAuthDetail oauthDetail, string mpAppID)
		{
			try
			{
				if (sessionCurrent == null || oauthDetail == null)
				{
					throw new BuzException("当前会话、授权信息不能为空");
				}
				if (string.IsNullOrEmpty(sessionCurrent.OpenID))
				{
					throw new BuzException("当前会话的OpenID不能为空");
				}
				using (var trans = context.Database.BeginTransaction())
				{
					try
					{
						#region 事务具体操作
						DateTime dtNow = DateTime.Now;
						string ip = GetRequestIP();

						Sys_OAuth oauth = context.SysOAuth.SingleOrDefault(e => e.AppID == appID && e.OpenID == sessionCurrent.OpenID);
						if (oauth == null)
						{
							throw new BuzException("第三方登录信息不存在");
						}
						oauth.UnionID = sessionCurrent.UnionID;
						oauth.Type = (int)oauthType;
						oauth.LastUpdate = dtNow;
						oauth.LastVisit = dtNow;
						oauth.NickName = oauthDetail.NickName;
						oauth.Gender = oauthDetail.Gender;
						oauth.Country = oauthDetail.Country;
						oauth.Province = oauthDetail.Province;
						oauth.City = oauthDetail.City;
						oauth.AvatarUrl = oauthDetail.AvatarUrl;
						oauth.Authorized = true;
						oauth.Subscribed = oauthDetail.Subscribe;
						context.SaveChanges();

						Sys_User user = context.SysUser.SingleOrDefault(e => e.ID == oauth.UserID);
						if (user == null)
						{
							throw new BuzException("第三方登录用户信息不存在");
						}
						user.NickName = oauthDetail.NickName;
						user.Gender = oauthDetail.Gender;
						user.Country = oauthDetail.Country;
						user.Province = oauthDetail.Province;
						user.City = oauthDetail.City;
						user.AvatarUrl = oauthDetail.AvatarUrl;
						user.LastLoginIP = ip;
						user.LastLoginDate = dtNow;
						if (user.StateNow == (int)UserState.未授权)
						{
							user.StateNow = (int)UserState.未绑定;
						}
						context.SaveChanges();

						Sys_Session session = context.SysSession.SingleOrDefault(e => e.UserID == user.ID && e.Type == (int)oauthType);
						if (session == null)
						{
							throw new BuzException("第三方登录用户会话信息不存在");
						}
						//session.Type = (int)oauthType;
						session.LastUpdate = dtNow;
						session.LastVisit = dtNow;
						session.LastVisitIP = ip;
						context.SaveChanges();
						#endregion

						trans.Commit();

						return GetUserSession(sessionCurrent, user, oauth, session);
					}
					catch (Exception ex)
					{
						trans.Rollback();
						throw ex;
					}
				}
			}
			catch (BuzException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (DbUpdateException ex)
			{
				logger.LogError(ex.InnerException ?? ex, "更新OAuth授权信息出错");
				throw new BuzException("更新OAuth授权信息失败，" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
			}
			catch (ArgumentException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.Message);
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException("更新OAuth授权信息失败，" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
			}
		}

		/// <summary>
		/// 刷新OAuth认证的基本信息，并返回更新后的值
		/// </summary>
		/// <returns></returns>
		public UserSession Refresh(UserSession sessionCurrent, SessionType type, string appID)
		{
			//根据openid刷新
			UserSession userSession = null;
			try
			{
				if (string.IsNullOrEmpty(appID) || sessionCurrent == null)
				{
					throw new ArgumentException("请求小程序、当前会话等参数不能为空");
				}

				if (logger.IsEnabled(LogLevel.Debug))
				{
					logger.LogDebug("刷新OAuth认证参数->type：{0}，appID：{1}，userCode：{2}，openid：{3}", type, appID, sessionCurrent.UserCode, sessionCurrent.OpenID);
				}

				DateTime dtNow = DateTime.Now;
				string ip = GetRequestIP();

				var oauth = context.SysOAuth.SingleOrDefault(m => m.AppID == appID && m.OpenID == sessionCurrent.OpenID);
				if (oauth == null)
				{
					throw new BuzException("未查询到相关oauth信息");
				}
				var session = context.SysSession.SingleOrDefault(m => m.UserID == oauth.UserID && m.Type == (int)type);
				if (session == null)
				{
					throw new BuzException("未查询到相关会话信息");
				}
				Sys_User userCurrent = null;
				if (sessionCurrent.UserID != oauth.UserID)
				{
					//检测当前登录账户是否与第三方登录绑定
					if (context.SysUserOAuth.Any(m => m.OAuthID == oauth.ID && m.UserID == sessionCurrent.UserID))
					{
						userCurrent = context.SysUser.SingleOrDefault(m => m.ID == sessionCurrent.UserID);//已绑定，使用绑定用户登录
					}
				}
				else
				{
					userCurrent = serviceUserOAuth.GetFirstOrDefaultUser(oauth.ID);//只有当前用户与oauth认证生成的用户一样时才获取绑定的用户信息，否则不用获取因为已经切换过
				}
				if (userCurrent == null)
				{
					userCurrent = context.SysUser.SingleOrDefault(m => m.ID == oauth.UserID);//没有绑定的话，还是使用oauth认证生成的用户
				}
				if (userCurrent == null)
				{
					throw new BuzException("未查询到当前登录的用户信息");
				}
				#region 更新数据库
				oauth.LastVisit = dtNow;
				oauth.LastVisitIP = ip;
				context.SaveChanges();

				session.LastVisit = dtNow;
				session.LastVisitIP = ip;
				context.SaveChanges();

				if (userCurrent != null)
				{
					userCurrent.LastLoginDate = dtNow;
					userCurrent.LastLoginIP = ip;
					context.SaveChanges();
				}
				#endregion

				userSession = GetUserSession(sessionCurrent, userCurrent, oauth, session);
			}
			catch (AuthException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.Message);
			}
			catch (ArgumentException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.Message);
			}
			catch (BuzException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException("刷新授权信息失败");
			}

			return userSession;
		}

		/// <summary>
		/// 使用用户名密码登录，登录成功后与当前会话绑定合并，返回更新后的会话信息
		/// </summary>
		/// <returns></returns>
		public UserSession Bind(UserSession sessionCurrent, SessionType sessionType, string appID, string userCode, string userPasswd, SysOAuthDetail oauthDetail)
		{
			try
			{
				if (sessionCurrent == null || sessionCurrent.UserID == 0)
				{
					throw new ArgumentException("未登录授权用户不能绑定");
				}
				if (string.IsNullOrEmpty(appID))
				{
					throw new ArgumentException("APPID不能为空");
				}
				if (string.IsNullOrEmpty(userCode) || string.IsNullOrEmpty(userPasswd))
				{
					throw new ArgumentException("用户名、密码不能为空");
				}

				using (var trans = context.Database.BeginTransaction())
				{
					try
					{
						DateTime dtNow = DateTime.Now;
						string ip = GetRequestIP();

						#region 查询操作
						var userToBind = context.SysUser.SingleOrDefault(m => m.Code == userCode);
						if (userToBind == null)
						{
							throw new BuzException("未查询到相关帐户信息");
						}
						if (userToBind.StateNow != (int)UserState.正常)
						{
							throw new BuzException("要绑定的用户状态不正常，无法绑定");
						}
						if (string.Compare(EncryptHelper.SHA1Hash(userPasswd + userToBind.PasswdSalt), userToBind.Passwd) != 0)
						{
							throw new BuzException("密码有误");
						}
						//if (userToBind.OrgID>0)
						//{
						//	var org = context.SysOrganization.FirstOrDefault(m => m.ID == userToBind.OrgID);
						//	if (null != org)
						//	{
						//		userToBind.OrgName = org.Name;
						//	}
						//}
						//根据appid和openid查找，不能根据当前用户的id查找，防止已经绑定
						var userOAuthCurrent = context.SysOAuth.SingleOrDefault(m => m.AppID == appID && m.OpenID == sessionCurrent.OpenID);
						if (userOAuthCurrent == null)
						{
							throw new BuzException("未查询到当前登录用户的oauth认证信息");
						}
						if (userOAuthCurrent.Type != (int)sessionType)
						{
							throw new BuzException("当前oauth登录的用户信息不一致");
						}

						var userCurrent = context.SysUser.SingleOrDefault(m => m.ID == userOAuthCurrent.UserID);
						if (userCurrent == null)
						{
							throw new BuzException("未查询到当前oauth认证的用户信息");
						}
						if (userToBind.ID != sessionCurrent.UserID)//如果要绑定的用户与当前用户不相同
						{
							context.Database.ExecuteSqlRaw("UPDATE Sys_UserOAuth SET Preferred={0} WHERE OAuthID={1}",
								false, userOAuthCurrent.ID);

							if (!context.SysUserOAuth.Any(m => m.OAuthID == userOAuthCurrent.ID && m.UserID == userToBind.ID))//未绑定
							{
								var userOAuth = new Sys_UserOAuth()
								{
									OAuthID = userOAuthCurrent.ID,
									UserID = userToBind.ID,
									Preferred = true,
									AddDate = dtNow
								};
								context.SysUserOAuth.Add(userOAuth);
								context.SaveChanges();
							}
						}

						#region 更新授权信息
						if (oauthDetail != null)
						{
							userOAuthCurrent.Authorized = true;
							userOAuthCurrent.NickName = oauthDetail.NickName;
							userOAuthCurrent.Gender = oauthDetail.Gender;
							userOAuthCurrent.AvatarUrl = oauthDetail.AvatarUrl;
							userOAuthCurrent.Country = oauthDetail.Country;
							userOAuthCurrent.Province = oauthDetail.Province;
							userOAuthCurrent.City = oauthDetail.City;
							userOAuthCurrent.LastUpdate = dtNow;
						}
						userOAuthCurrent.LastVisit = dtNow;
						userOAuthCurrent.LastVisitIP = ip;
						context.SaveChanges();
						#endregion

						//绑定后的新会话信息
						var userSessionNew = context.SysSession.SingleOrDefault(m => m.UserID == userToBind.ID && m.Type == (int)sessionType);
						if (userSessionNew == null)
						{
							userSessionNew = new Sys_Session()
							{
								UserID = userToBind.ID,
								Type = (int)sessionType,
								AddTime = dtNow,
								LastUpdate = dtNow,
								LastVisit = dtNow,
								LastVisitIP = ip,
								SessionKey = userOAuthCurrent.SessionKey,
							};
							context.SysSession.Add(userSessionNew);
							context.SaveChanges();
						}
						else
						{
							userSessionNew.SessionKey = userOAuthCurrent.SessionKey;
							userSessionNew.LastUpdate = dtNow;
							userSessionNew.LastVisit = dtNow;
							userSessionNew.LastVisitIP = ip;
							context.SaveChanges();
						}

						#region 更新绑定的用户信息
						userToBind.LastLoginDate = dtNow;
						userToBind.LastLoginIP = ip;
						context.SaveChanges();
						#endregion

						#region 更新原oauth认证生成的用户信息
						if (oauthDetail != null)
						{
							userCurrent.NickName = oauthDetail.NickName;
							userCurrent.Gender = oauthDetail.Gender;
							userCurrent.AvatarUrl = oauthDetail.AvatarUrl;
							userCurrent.Country = oauthDetail.Country;
							userCurrent.Province = oauthDetail.Province;
							userCurrent.City = oauthDetail.City;
						}
						userCurrent.StateNow = (int)UserState.正常;
						userCurrent.OrgID = userToBind.OrgID;
						userCurrent.LastLoginDate = dtNow;
						userCurrent.LastLoginIP = ip;
						context.SaveChanges();
						#endregion
						#endregion

						//#region 合并会话，只是修改userid指向，如果解绑后可以重新看到原userid相关数据
						////将当前oauth绑定的userid修改为新的userid
						//userOAuthCurrent.UserID = userToBind.ID;
						//userOAuthCurrent.LastUpdate = dtNow;
						//userOAuthCurrent.LastVisit = dtNow;
						//context.SaveChanges();
						//#endregion

						trans.Commit();

						//返回合并后的会话
						UserSession userSession = GetUserSession(sessionCurrent, userToBind, userOAuthCurrent, userSessionNew);
						return userSession;
					}
					catch (Exception ex)
					{
						trans.Rollback();
						throw ex;
					}
				}
			}
			catch (ArgumentException ex)
			{
				logger.LogError(ex.InnerException ?? ex, "用户名密码登录绑定出错");
				throw ex;
			}
			catch (BuzException ex)
			{
				throw ex;
			}
			catch (DbUpdateException ex)
			{
				logger.LogError(ex.InnerException ?? ex, "用户名密码登录绑定出错");
				throw new BuzException("用户登录失败，" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, "用户名密码登录绑定出错");
				throw new BuzException("用户登录失败，" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
			}
		}

		/// <summary>
		/// 将小程序用户与公众号用户绑定，绑定成功后与当前会话绑定合并，返回更新后的会话信息
		/// </summary>
		/// <param name="sessionCurrent"></param>
		/// <param name="appID">小程序appid</param>
		/// <param name="oauthInfo"></param>
		/// <returns></returns>
		public UserSession MPBind(UserSession sessionCurrent, string appID, SysOAuthDetail oauthDetail)
		{
			try
			{
				if (sessionCurrent == null || sessionCurrent.UserID == 0 || string.IsNullOrEmpty(sessionCurrent.OpenID))
				{
					throw new ArgumentException("未登录授权用户不能绑定");
				}
				if (string.IsNullOrEmpty(appID))
				{
					throw new ArgumentException("小程序appid不能为空");
				}
				if (oauthDetail == null || string.IsNullOrEmpty(oauthDetail.AppID))
				{
					throw new ArgumentException("公众号appid不能为空");
				}
				if (string.IsNullOrEmpty(oauthDetail.OpenID))
				{
					throw new ArgumentException("公众号授权信息不能为空");
				}
				using (var trans = context.Database.BeginTransaction())
				{
					try
					{
						#region 事务具体操作
						DateTime dtNow = DateTime.Now;
						int userIDMP = 0;
						string ip = GetRequestIP();
						string userCodeMP = EncryptHelper.MD5Hash(oauthDetail.AppID + oauthDetail.OpenID);//根据appid和openid生成usercode，然后查找用户表看之前是否授权登录过
						Sys_OAuth oauthMP = null;
						Sys_User userMP = null;
						Sys_Session sessionMP = null;
						oauthMP = context.SysOAuth.SingleOrDefault(e => e.AppID == oauthDetail.AppID && e.OpenID == oauthDetail.OpenID);
						if (oauthMP != null && oauthMP.UserID > 0)
						{
							userMP = context.SysUser.SingleOrDefault(m => m.ID == oauthMP.UserID);//获取oauth授权登录生成的user信息
						}
						else
						{
							userMP = context.SysUser.SingleOrDefault(e => e.Code == userCodeMP);//如果没绑定根据生成的code查询
						}

						if (userMP == null)
						{
							userMP = new Sys_User()
							{
								Code = userCodeMP,
								PasswdSalt = Guid.NewGuid().ToString("N"),
								StateNow = string.IsNullOrEmpty(oauthDetail.AvatarUrl) ? (int)UserState.未授权 : (int)UserState.未绑定,
								AddDate = dtNow,
							};
							userMP.Passwd = EncryptHelper.SHA1Hash(oauthDetail.OpenID + userMP.PasswdSalt);
						}
						userMP.LastLoginDate = dtNow;
						userMP.LastLoginIP = ip;
						userIDMP = RegisterOrLogin(userMP, oauthDetail);

						if (oauthMP == null)
						{
							oauthMP = new Sys_OAuth
							{
								AppID = oauthDetail.AppID,
								OpenID = oauthDetail.OpenID,
								AddDate = dtNow,
							};
						}
						oauthMP.UserID = userIDMP;
						oauthMP.UnionID = oauthDetail.UnionID;
						oauthMP.Type = (int)oauthDetail.Type;
						oauthMP.SessionKey = oauthDetail.SessionKey;
						oauthMP.LastUpdate = dtNow;
						oauthMP.LastVisit = dtNow;
						oauthMP.LastVisitIP = ip;
						#region 设置用户oauth信息
						oauthMP.Authorized = !string.IsNullOrEmpty(oauthDetail.AvatarUrl);
						oauthMP.Subscribed = oauthDetail.Subscribe;
						oauthMP.NickName = oauthDetail.NickName;
						oauthMP.Gender = oauthDetail.Gender;
						oauthMP.AvatarUrl = oauthDetail.AvatarUrl;
						oauthMP.Country = oauthDetail.Country;
						oauthMP.Province = oauthDetail.Province;
						oauthMP.City = oauthDetail.City;
						oauthMP.District = oauthDetail.District;
						oauthMP.Town = oauthDetail.Town;
						oauthMP.DetailAddress = oauthDetail.DetailAddress;
						#endregion
						if (oauthMP.ID == 0)
						{
							context.SysOAuth.Add(oauthMP);
						}
						context.SaveChanges();

						sessionMP = context.SysSession.SingleOrDefault(e => e.UserID == userIDMP && e.Type == (int)oauthDetail.Type);//同一个用户同一种登录类型只能有一条记录
						if (sessionMP == null)
						{
							sessionMP = new Sys_Session
							{
								UserID = userIDMP,
								Type = (int)oauthDetail.Type,
								AddTime = dtNow,
							};
						}
						sessionMP.SessionKey = oauthDetail.SessionKey;
						sessionMP.LastUpdate = dtNow;
						sessionMP.LastVisit = dtNow;
						sessionMP.LastVisitIP = ip;
						if (sessionMP.ID == 0)
						{
							context.SysSession.Add(sessionMP);
						}
						context.SaveChanges();

						#region 获取绑定的用户信息
						Sys_OAuth oauthXCX = context.SysOAuth.SingleOrDefault(m => m.AppID == appID && m.OpenID == sessionCurrent.OpenID);
						if (oauthXCX == null)
						{
							throw new ArgumentException("小程序授权信息不存在");
						}
						oauthXCX.RelatedOAuthID = oauthMP.ID;//设置小程序关联的公众号openid
						context.SaveChanges();

						if (sessionCurrent.UserID != userIDMP && sessionCurrent.UserID != oauthXCX.UserID)//如果当前用户已绑定系统中其他用户，那么公众号也绑定到该用户
						{
							context.Database.ExecuteSqlRaw("UPDATE Sys_UserOAuth SET Preferred={0} WHERE OAuthID={1}",
								false, oauthMP.ID);

							var userOAuth = context.SysUserOAuth.SingleOrDefault(m => m.OAuthID == oauthMP.ID && m.UserID == sessionCurrent.UserID);
							if (userOAuth == null)//未绑定
							{
								userOAuth = new Sys_UserOAuth()
								{
									OAuthID = oauthMP.ID,
									UserID = sessionCurrent.UserID,
									Preferred = true,
									AddDate = dtNow
								};
								context.SysUserOAuth.Add(userOAuth);
								context.SaveChanges();
							}
							else
							{
								userOAuth.Preferred = true;
								context.SaveChanges();
							}
						}
						#endregion

						#endregion
						trans.Commit();

						sessionCurrent.RelatedOpenID = oauthDetail.OpenID;//修改当前会话的公众号openid
						sessionCurrent.Subscribe = oauthDetail.Subscribe;
						//if (oauthXCX.UserID == sessionCurrent.UserID)//todo:设置当前用户的状态，当前登录的为小程序登录
						//{
						//}

						return sessionCurrent;
					}
					catch (Exception ex)
					{
						trans.Rollback();
						throw ex;
					}
				}
			}
			catch (ArgumentException ex)
			{
				logger.LogError(ex.InnerException ?? ex, "绑定公众号用户出错");
				throw ex;
			}
			catch (BuzException ex)
			{
				throw ex;
			}
			catch (DbUpdateException ex)
			{
				logger.LogError(ex.InnerException ?? ex, "绑定公众号用户出错");
				throw new BuzException("绑定公众号用户失败，" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, "绑定公众号用户出错");
				throw new BuzException("绑定公众号用户失败，" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
			}
		}

		/// <summary>
		/// 解除绑定
		/// </summary>
		/// <returns></returns>
		public UserSession Unbind(UserSession sessionCurrent, string appID)
		{
			throw new NotImplementedException();
		}

		public void DeleteByUserID(int userID)
		{
			//先删除当前用户的关联记录
			context.Database.ExecuteSqlRaw("DELETE FROM Sys_UserOAuth WHERE OAuthID=(SELECT ID FROM Sys_OAuth WHERE UserID={0})", userID);
			context.Database.ExecuteSqlRaw("DELETE FROM Sys_OAuth WHERE UserID={0}", userID);
		}

		private int RegisterOrLogin(Sys_User user, SysOAuthDetail oauthDetail)
		{
			user.StateNow = user.StateNow == 0 ? (int)UserState.未授权 : user.StateNow;
			if (oauthDetail != null)
			{
				//user.StateNow = user.StateNow == (int)UserState.未授权 ? (int)UserState.未绑定 : user.StateNow;
				#region 设置用户oauth信息
				user.NickName = oauthDetail.NickName;
				user.Gender = oauthDetail.Gender;
				user.AvatarUrl = oauthDetail.AvatarUrl;
				user.Country = oauthDetail.Country;
				user.Province = oauthDetail.Province;
				user.City = oauthDetail.City;
				user.District = oauthDetail.District;
				user.Town = oauthDetail.Town;
				user.DetailAddress = oauthDetail.DetailAddress;
				#endregion
			}
			if (user.ID == 0)
			{
				context.SysUser.Add(user);
			}
			context.SaveChanges();
			return user.ID;
		}
	}
}